package cn.ibizlab.odoo.util.feign.suport;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import cn.ibizlab.odoo.util.helper.SpringContextHolder;
import cn.ibizlab.odoo.util.SearchContext;
import cn.ibizlab.odoo.util.security.userdetail.LoginUser;
import cn.ibizlab.odoo.util.web.SessionConstants;

@Slf4j
public class SearchContextFeignEncode  implements Encoder {

	private final Encoder delegate;

	public SearchContextFeignEncode(Encoder delegate) {
		this.delegate = delegate;
	}

	@Override
	public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
		LoginUser loginUser = SpringContextHolder.getCurLoginUser();
		if (loginUser != null) {
			template.header(SessionConstants.PERSONID, loginUser.getPersonId());
			template.header(SessionConstants.ORGUSERID, loginUser.getOrgUserId());
			template.header(SessionConstants.ORGUSERNAME, loginUser.getOrgUserName());
			template.header(SessionConstants.ORGID, loginUser.getOrgId());
			template.header(SessionConstants.ORGNAME, loginUser.getOrgName());
			template.header(SessionConstants.ORGSECTORID, loginUser.getOrgDeptId());
			template.header(SessionConstants.ORGSECTORNAME, loginUser.getOrgDeptName());
		}

		if (supports(object)) {
			if (object instanceof SearchContext) {
				SearchContext searchContext = (SearchContext) object;
				if (searchContext.getPageable().isPaged()) {
					template.query("page", searchContext.getPageable().getPageNumber() + "");
					template.query("size", searchContext.getPageable().getPageSize() + "");
				}

				if (searchContext.getPageable().getSort() != null) {
					applySort(template, searchContext.getPageable().getSort());
				}
				delegate.encode(object, bodyType, template);
			}
		}
		else {
			if (delegate != null) {
				delegate.encode(object, bodyType, template);
			}
			else {
				throw new EncodeException(
						"PageableSpringEncoder does not support the given object "
								+ object.getClass()
								+ " and no delegate was provided for fallback!");
			}
		}
	}

	private void applySort(RequestTemplate template, Sort sort) {
		String sortParameter = "sort" ;
		Collection<String> existingSorts = template.queries().get("sort");
		List<String> sortQueries = existingSorts != null ? new ArrayList<>(existingSorts)
				: new ArrayList<>();
		if (!sortParameter.equals("sort")) {
			existingSorts = template.queries().get(sortParameter);
			if (existingSorts != null) {
				sortQueries.addAll(existingSorts);
			}
		}
		for (Sort.Order order : sort) {
			sortQueries.add(order.getProperty() + "," + order.getDirection());
		}
		if (!sortQueries.isEmpty()) {
			template.query(sortParameter, sortQueries);
		}
	}

	protected boolean supports(Object object) {
		return object instanceof SearchContext ;
	}

}
